pub mod bits;
pub mod canvas;
mod cast;
pub mod ec;
pub mod generator;
pub mod optimize;
pub mod render;
pub mod types;

pub use generator::QrCode;
pub use render::image::Luma;
pub use types::{EcLevel, Version};

use std::ffi::CStr;
use std::mem::forget;
use std::os::raw::c_char;
use std::slice::from_raw_parts_mut;

#[repr(C)]
struct Buffer {
  data: *mut u8,
  len: usize,
}

#[no_mangle]
extern "C" fn generate_normal(
  buf: *const c_char,
  version: i16,
  ec_level: u8,
) -> Buffer {
  let ec_level = match ec_level {
    0 => EcLevel::L,
    1 => EcLevel::M,
    2 => EcLevel::Q,
    3 => EcLevel::H,
    _ => EcLevel::H,
  };
  let buf = unsafe { CStr::from_ptr(buf) }.to_str().unwrap().as_bytes();
  let code =
    QrCode::with_version(buf, Version::Normal(version), ec_level).unwrap();
  let image = code.render::<Luma<u8>>().build();
  let mut data = image.into_raw().into_boxed_slice();
  let len = data.len();
  let data = data.as_mut_ptr();
  forget(data);
  Buffer { data, len }
}

#[no_mangle]
extern "C" fn generate(buf: *const c_char) -> Buffer {
  let buf = unsafe { CStr::from_ptr(buf) }.to_str().unwrap().as_bytes();
  let code = QrCode::new(buf).unwrap();
  let image = code.render::<Luma<u8>>().build();
  let mut data = image.into_raw().into_boxed_slice();
  let len = data.len();
  let data = data.as_mut_ptr();
  forget(data);
  Buffer { data, len }
}

#[no_mangle]
extern "C" fn free_buf(buf: Buffer) {
  let s = unsafe { from_raw_parts_mut(buf.data, buf.len) };
  unsafe {
    Box::from_raw(s as *mut [u8]);
  }
}
